package com.sitech.ibnms.c3p.task.aspect;

import com.sitech.ibnms.c3p.command.CommandParamsService;
import com.sitech.ibnms.c3p.domain.C3pBranchDecisionResult;
import com.sitech.ibnms.c3p.domain.C3pTaskNodeIo;
import com.sitech.ibnms.c3p.domain.C3pTaskNodeVars;
import com.sitech.ibnms.c3p.mappers.C3pBranchDecisionResultMapper;
import com.sitech.ibnms.c3p.mappers.C3pTaskMapper;
import com.sitech.ibnms.c3p.mappers.C3pTaskNodeVarsMapper;
import com.sitech.ismp.workflow.domain.Task;
import com.sitech.ismp.workflow.engine.WorkFLowConst;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.List;

/**
 * Created by liujhc on 7/24.
 */
@Aspect
@Component
public class ORBranchAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private C3pTaskNodeVarsMapper nodeExtMapper;
    @Autowired
    private C3pBranchDecisionResultMapper decisionResultMapper;
    @Autowired
    private CommandParamsService paramsService;
    @Autowired
    private C3pTaskMapper c3pTaskMapper;

    /**
     * 在或分支之前准备期望结果
     *
     * @param task
     */
    @AfterReturning(value = "execution(com.sitech.ismp.workflow.domain.Task com.sitech.ismp.workflow.engine.TaskManager.addToDoTask(com.sitech.ismp.workflow.domain.Task))",
            returning = "task")
    public void preProcessORBRANCH(final Task task) throws Throwable {
        int serialNo = task.getSerialNo();
        int processId = task.getProcessId();
        int activityId = task.getCurrActId();
        int taskId = task.getTaskId();
        logger.debug("AddToDoTask[processId={}, serialNo={}, taskId={}]", processId, serialNo, taskId);
        if (task != null && task.getActivityType() == WorkFLowConst.ACTIVITY_TYPE_OR_BRANCH) {
            logger.info("Current task[{}] is OR-BRANCH activity!", taskId);
            String c3pTaskId = c3pTaskMapper.queryC3pTaskIdByProcessId(processId);
            // 准备表达式执行环境
            logger.debug("Prepare to expression execution engine...");
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
            List<C3pTaskNodeIo> preParamsOut = paramsService.queryParamsOut(serialNo);
            for (C3pTaskNodeIo param : preParamsOut) {
                String name = param.getParamName();
                String value = param.getParamValue();
                logger.debug("Put param to execution context: {}={}", name, value);
                engine.put(name, value);
            }
            // 取得表达式，依次执行
            List<C3pTaskNodeVars> nodeExts = nodeExtMapper.queryParamsInConf(processId, activityId);
            logger.debug("There are {} expressions to execute!", nodeExts.size());
            for (C3pTaskNodeVars nodeExt : nodeExts) {
                // value为表达式，key为对应的activityId
                String expression = nodeExt.getVarValue();
                logger.debug("Execute expression: {}", expression);
                if (StringUtils.isNoneBlank(expression)) {
                    try {
                        Object val = engine.eval(String.format("(%s)", expression));
                        logger.debug("EXPRESSION[{}] execution complete: {}", expression, val);
                        if (Boolean.TRUE.equals(val)) {
                            // 执行结果为true，表达式不再继续执行
                            C3pBranchDecisionResult result = new C3pBranchDecisionResult();
                            result.setC3pTaskId(c3pTaskId);
                            result.setProcessId(processId);
                            result.setWfSerialNo(serialNo);
                            result.setActivityId(task.getCurrActId());
                            result.setWorklistId(task.getInstanceId());
                            result.setEmployeeId(task.getCurrDealer());
                            result.setDecisionResult(nodeExt.getVarName());
                            logger.info("{}", result);
                            decisionResultMapper.insertDecisionResult(result);
                            return;
                        } else if (!(val instanceof Boolean)) {
                            logger.error("OR-BRANCH expression result type is not boolean: {}", nodeExt);
                        }
                    } catch (ScriptException e) {
                        logger.error(String.format("OR-BRANCH expression execution error: %s", nodeExt), e);
                    }
                }
            }
        }
    }
}
